package com.jpa.sepcification.demo.test.service;

import com.jpa.sepcification.demo.test.domain.UserDO;
import com.jpa.sepcification.demo.test.repository.UserRepository;
import com.jpa.sepcification.demo.test.service.dto.UserDTO;
import com.jpa.sepcification.demo.test.service.mapper.UserMapper;
import com.jpa.sepcification.demo.utils.specification.Specifications;
import com.jpa.sepcification.demo.web.test.vo.UserVO;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;


/**
 * User service层
 *
 * @author zcj
 * @date 2020-12-28 13:34:38
 */
@Service
public class UserService {

	private final UserRepository userRepository;
	private final UserMapper userMapper;

	public UserService(UserMapper userMapper,
					   UserRepository userRepository) {
		this.userMapper = userMapper;
		this.userRepository = userRepository;
	}


	/**
	 * 条件查询所有
	 *
	 * @param userVO 查询条件
	 * @return 所有符合条件的列表
	 */
	public List<UserDTO> findAll(UserVO userVO) {
		Specification<UserDO> spec = this.getAllSpecification(userVO);
		return userRepository.findAll(spec).stream().map(userMapper::entityToDTO).collect(Collectors.toList());
	}

	/**
	 * 获取所有查询条件的specification
	 *
	 * @param userVO 查询条件
	 * @return specification
	 */
	private Specification<UserDO> getAllSpecification(UserVO userVO) {
		/**
		 * 发送请求 localhost:8090/api/users/all?name=周&createdDate=2020-1-1&createdDate=2020-12-31&phone=18888888888后
		 *
		 *
		 * sql为:
		 * SELECT
		 * 	*
		 * FROM
		 * USER
		 * WHERE
		 * 	version > 0
		 * 	AND (
		 * 		email =?
		 * 	    OR phone =?
		 * 	)
		 * 	AND ( created_ts BETWEEN ? AND ? )
		 * 	AND ( NAME LIKE ? )
		 *
		 */
		return Specifications.<UserDO>and()
				// 直接使用的方式会判断后面的参数是否为空，如果为空就不会起作用
				// 如果第二个参数为空，则不会生效
				.equal("userName", userVO.getUserName())
				.like("name", userVO.getName())
				// 实体类中的类型为Instant 就使用betweenInstant，为Date就使用betweenDate 参数为List<String>  日期格式为yyyy-MM-dd
				.betweenInstant("createdDate", userVO.getCreatedDate())
				// 相当于or里面的内容加了个括号
				.and(Specifications.<UserDO>or()
						.equal("phone", userVO.getPhone())
						.equal("email", "email不相等")
						.build())
				// 如果没有找到与你期望的预设方法，可以使用下面的方法自定义条件
				.and((root, query, builder) -> builder.greaterThan(root.get("version"), 0))
				// 直接修改后面的方法为or 不太实用，最好还是使用or(Specification spec)
//				.or()
//				.like("avatar", "这里是肯定不等于值的，只是做个测试")
				.build();
	}


}
